home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / protobnu.lqr / PROTOCOL.PAS next >
Pascal/Delphi Source File  |  1985-06-13  |  21KB  |  718 lines

  1. {***************
  2. **
  3. **  This module implements the B-Protocol Functions for terminal.pas.
  4. **  The only procedures this routine requires that are not located here
  5. **  are send and cgetc.  These routines should be as follows:
  6. **
  7. **  procedure send(ch : integer);
  8. **  (*This procedure sends the character who's ordinal value is CH to the
  9. **    async port*)
  10. **
  11. **  function cgetc(wait_time : integer) : integer;
  12. **  (*This function waits approximately WAIT_TIME seconds for a character
  13. **    at the async port.  If no character is received, -1 is returned,
  14. **    otherwise the ordinal value of the received character is returned*)
  15. **
  16. **  These definitions should be sufficient to implement B-Protocol in a
  17. **  pascal program.  The routine DO_TRANSFER should be invoked whenever a
  18. **  ENQ (ascii value 5) is received from the host.  It returns TRUE if the
  19. **  operation it performs is successful.
  20. **
  21. **  If you have any questions contact me, Jim Nutt, at either 76044,1155 or
  22. **  71076,1434 on CIS, or at FIDOnet Node 452.
  23. ****************}
  24.  
  25. function do_transfer : boolean;
  26.  
  27.   const   xmt_size     = 511;
  28.           rcv_size     = 512;
  29.           max_errors   =  10;
  30.  
  31. { Sender actions }
  32.  
  33.           s_send_packet  = 0;
  34.           s_get_dle      = 1;
  35.           s_get_num      = 2;
  36.           s_get_seq      = 3;
  37.           s_get_data     = 4;
  38.           s_get_checksum = 5;
  39.           s_timed_out    = 6;
  40.           s_send_nak     = 7;
  41.  
  42. { Receiver actions }
  43.  
  44.           r_get_dle      = 0;
  45.           r_get_b        = 1;
  46.           r_get_seq      = 2;
  47.           r_get_data     = 3;
  48.           r_get_checksum = 4;
  49.           r_send_nak     = 5;
  50.           r_send_ack     = 6;
  51.  
  52. {Other Constants}
  53.  
  54.           xmt_col = 50;
  55.           rcv_col = 36;
  56.           xon  = 17;
  57.           xoff = 19;
  58.           dle  = 16;
  59.           etx  = 03;
  60.           nak  = 21;
  61.           enq  = 05;
  62.           wack = 59;
  63.  
  64.  
  65.   type lstr    = string[255];
  66.        buffertype = array[0..520] of byte;
  67.        bytefile = file of byte;
  68.  
  69.   var
  70.     timer,
  71.     r_size,                                { size of receiver buffer }
  72.     checksum,
  73.     seq_num,
  74.     ch : integer;                               { current character }
  75.  
  76.     xoff_flag,
  77.     timed_out,                                { we timed out before receiving character }
  78.     masked : boolean;
  79.     { true if ctrl character was 'masked' }
  80.  
  81.     s_buffer : buffertype;
  82.     r_buffer : buffertype;
  83.     filename : lstr;                        { pathname }
  84.     i, n     : integer;
  85.     dummy    : boolean;
  86.     s_counter  : byte;
  87.     r_counter  : byte;
  88.  
  89. procedure send_masked_byte(ch : integer);
  90.  
  91. begin
  92.   if ch < 32
  93.     then
  94.       begin
  95.         send(dle);
  96.         send(ch + ord('@'));
  97.       end
  98.     else
  99.       send(ch);
  100.     s_counter := (s_counter + 1) mod 64;
  101.     if s_counter = 0 then write('.');
  102. end;
  103.  
  104. procedure send_ack;
  105. begin
  106.   write('!');
  107.   send(dle);
  108.   send(seq_num + ord('0'));
  109. end;
  110.  
  111. procedure send_nak;
  112. begin
  113.   write('?');
  114.   send(nak);
  115. end;
  116.  
  117.  
  118. procedure send_enq;
  119. begin
  120.   write('¿');
  121.   send(enq);
  122. end;
  123.  
  124. function read_byte : boolean;
  125.  
  126. begin
  127.  
  128.   timed_out := false;
  129.  
  130.   ch := cgetc(timer);
  131.  
  132.   if ch < 0 then
  133.     begin
  134.     read_byte := false;
  135.     exit;
  136.     end;
  137.  
  138.   r_counter := (r_counter + 1) mod 64;
  139.   if r_counter = 0 then write('+');
  140.   read_byte :=  true;
  141. end;
  142.  
  143.  
  144. function read_masked_byte : boolean;
  145.  
  146. begin
  147.   masked := false;
  148.  
  149.   if (read_byte = false)
  150.     then begin
  151.            read_masked_byte := false;
  152.            exit;
  153.       end;
  154.  
  155.   if (ch = dle)
  156.     then
  157.       begin
  158.         if (read_byte = false)
  159.           then begin
  160.                  read_masked_byte := false;
  161.                  exit;
  162.             end;
  163.         ch := ch and $1f;
  164.         masked := true;
  165.       end;
  166.  
  167.   read_masked_byte := true;
  168. end;
  169.  
  170.  
  171. procedure do_checksum(ch : integer);
  172.  
  173. begin
  174.   checksum := checksum shl 1;
  175.   if (checksum > 255)
  176.     then checksum := (checksum and $ff) + 1;
  177.   checksum := checksum + ch;
  178.   if (checksum > 255)
  179.     then checksum := (checksum and $ff) + 1;
  180. end;
  181.  
  182. function send_packet(size: integer) : boolean;
  183.  
  184. var
  185.   action,
  186.   errors,
  187.   next_seq,
  188.   block_num,
  189.   i : integer;
  190.   sent_enq :     boolean;
  191.  
  192. begin
  193.  
  194.   next_seq := (seq_num + 1) mod 10;
  195.   errors := 0;
  196.   sent_enq := false;
  197.   action := s_send_packet;
  198.   writeln;
  199.  
  200.   while true do
  201.     case (action) of
  202.       s_send_packet: begin
  203.                        checksum := 0;
  204.                        send(dle);
  205.                        send(ord('B'));
  206.                        send(next_seq + ord('0'));
  207.                        do_checksum(next_seq + ord('0'));
  208.  
  209.                        for i := 0 to  size do
  210.                          begin
  211.                            send_masked_byte(s_buffer[i]);
  212.                            do_checksum(s_buffer[i]);
  213.                          end;
  214.  
  215.                        send(etx);
  216.                        do_checksum(etx);
  217.                        send_masked_byte(checksum);
  218.                        action := s_get_dle;
  219.                      end;
  220.  
  221.       s_get_dle: begin
  222.                    timer := 30;
  223.  
  224.                    if (read_byte = false)
  225.                      then action := s_timed_out
  226.                      else if (ch = dle)
  227.                             then action := s_get_num
  228.                             else if (ch = nak)
  229.                                    then
  230.                                      begin
  231.                                        errors := errors + 1;
  232.                                        if (errors > max_errors)
  233.                                          then begin
  234.                                                 send_packet := false;
  235.                                                 exit;
  236.                                            end;
  237.                                        action := s_send_packet;
  238.                                      end
  239.                                    else if (ch = etx)
  240.                                           then action := s_send_nak;
  241.  
  242.                  end;
  243.       s_get_num: begin
  244.                    timer := 30;
  245.  
  246.                    if (read_byte = false)
  247.                      then action := s_timed_out
  248.                      else if (ch >= ord('0')) and (ch <= ord('9'))
  249.                             then
  250.                               begin
  251.  
  252.                                 if (ch - ord('0') = seq_num)
  253.                                   then
  254.                                     if (sent_enq)
  255.                                       then action := s_send_packet
  256.                                       else action := s_get_dle
  257.                                   else
  258.                                     if (ch - ord('0') = next_seq)
  259.                                       then
  260.                                         begin
  261.                                           seq_num := next_seq;
  262.                                           send_packet := true;
  263.                                           exit
  264.                                         end
  265.                                       else
  266.                                         if (errors = 0)
  267.                                           then action := s_send_packet
  268.                                           else action := s_get_dle;
  269.  
  270.                               end
  271.                             else if (ch = nak)
  272.                                    then action := s_send_packet
  273.                                    else if (ch = wack)
  274.                                           then
  275.                                             begin
  276.                                               timer := timer + 10;
  277.                                               action := s_get_dle;
  278.                                             end
  279.                                           else if (ch = ord('B'))
  280.                                                  then action := s_get_seq
  281.                                                  else if (ch = etx)
  282.                                                         then action := s_send_nak
  283.                                                         else action := s_get_dle;
  284.                  end;
  285.  
  286.       s_get_seq: begin
  287.                    timer := 10;
  288.  
  289.                    if (read_byte = false)
  290.                      then action := s_send_nak
  291.                      else
  292.                        begin
  293.                          checksum := 0;
  294.                          block_num := ch - ord('0');
  295.                          do_checksum(ch);
  296.                          i := 0;
  297.                          action := s_get_data;
  298.                        end;
  299.  
  300.                  end;
  301.       s_get_data: begin
  302.                     timer := 10;
  303.  
  304.                     if (read_masked_byte = false)
  305.                       then action := s_send_nak
  306.                       else if ((ch = etx) and not masked)
  307.                              then
  308.                                begin
  309.                                  do_checksum(etx);
  310.                                  action := s_get_checksum;
  311.                                end
  312.                              else
  313.                                begin
  314.                                  r_buffer[i] := ch;
  315.                                  i := i + 1;
  316.                                  do_checksum(ch);
  317.                                end;
  318.  
  319.                   end;
  320.  
  321.       s_get_checksum: begin
  322.                         timer := 10;
  323.  
  324.                         if (read_masked_byte = false)
  325.                           then action := s_send_nak
  326.                           else if (ch <> checksum)
  327.                                  then action := s_send_nak
  328.                                  else if (block_num <> (next_seq + 1) mod 10)
  329.                                         then action := s_send_nak
  330.                                         else
  331.                                           begin
  332.                                             seq_num := block_num;
  333.                                             send_ack;
  334.                                             r_size := i;
  335.                                             send_packet :=  true;
  336.                                             exit;
  337.                                           end;
  338.  
  339.                       end;
  340.  
  341.       s_timed_out: begin
  342.                      errors := errors + 1;
  343.                      if (errors > 4)
  344.                        then begin
  345.                               send_packet := false;
  346.                               exit;
  347.                          end;
  348.                      action := s_get_dle;
  349.                    end;
  350.  
  351.       s_send_nak: begin
  352.                     errors := errors + 1;
  353.                     if (errors > max_errors)
  354.                       then begin
  355.                              send_packet := false;
  356.                              exit;
  357.                         end;
  358.                     send_nak;
  359.                     action := s_get_dle;
  360.                   end;
  361.     end;
  362.  
  363. end; { Send_Packet }
  364.  
  365.  
  366. procedure send_failure(code : char);
  367.  
  368. var dummy : boolean;
  369.  
  370. begin
  371.   s_buffer[0] := ord('F');
  372.   s_buffer[1] := ord(code);
  373.   dummy := send_packet(2);
  374. end;
  375.  
  376.  
  377. function read_file(var data_file : bytefile; var s_buffer : buffertype;
  378.                    n, xmt_size : integer) : integer;
  379.  
  380. var i : integer;
  381.  
  382. begin
  383.   i := n;
  384.   while (not eof(data_file)) and (xmt_size > 0) do
  385.     begin
  386.       read(data_file,s_buffer[i]);
  387.       i := i + 1;
  388.       xmt_size := xmt_size - 1;
  389.     end;
  390.   read_file := i - n;
  391. end;
  392.  
  393. function send_file(name : lstr) : boolean;
  394.  
  395. var n : integer;
  396.   data_file : bytefile;
  397.  
  398. begin
  399.  
  400.   assign(data_file,name);
  401. {$i-}
  402.   reset(data_file);
  403. {$i+}
  404.  
  405.   if (ioresult > 0)
  406.     then
  407.       begin
  408.         send_failure('E');
  409.         begin
  410.           send_file := false;
  411.           exit;
  412.         end
  413.       end;
  414.  
  415.   repeat
  416.     s_buffer[0] := ord('N');
  417.     n := read_file(data_file, s_buffer,1, xmt_size);
  418.  
  419.     if (n > 0)
  420.       then
  421.         begin
  422.  
  423.           if (send_packet(n) = false)
  424.             then
  425.               begin
  426.                 begin
  427.                   send_file := false;
  428.                   exit;
  429.                 end
  430.               end;
  431.  
  432.         end;
  433.   until not (n > 0);
  434.  
  435. { Inform host that the file was sent }
  436.  
  437.   s_buffer[0] := ord('T');
  438.   s_buffer[1] := ord('C');
  439.  
  440.   if (send_packet(2) = false)
  441.     then
  442.       begin
  443.         begin
  444.           send_file := false;
  445.           exit;
  446.         end
  447.       end
  448.     else
  449.       begin
  450.         close(data_file);
  451.         send_file := true;
  452.         exit;
  453.       end;
  454.  
  455. end; { Send_File }
  456.  
  457. function read_packet : boolean;
  458.  
  459. {True if packet is available from host}
  460.  
  461. var
  462.   action,
  463.   next_seq,
  464.   block_num,
  465.   errors,
  466.   i : integer;
  467.  
  468. begin
  469.   fillchar(r_buffer,520,0);
  470.   next_seq := (seq_num +  1) mod 10;
  471.   errors := 0;
  472.   action := r_get_dle;
  473.   writeln;
  474.  
  475.   while true do
  476.     begin
  477.       timer := 10;
  478.  
  479.       case  (action) of
  480.         r_get_dle: begin
  481.                      if (read_byte = false)
  482.                        then action := r_send_nak
  483.                        else if ((ch and$7F) = dle)
  484.                               then action := r_get_b
  485.                               else if ((ch and $7F) = enq)
  486.                                      then action := r_send_ack;
  487.                    end;
  488.  
  489.         r_get_b: begin
  490.                    if (read_byte = false)
  491.                      then action := r_send_nak
  492.                      else if ((ch and $7F) = ord('B'))
  493.                             then action := r_get_seq
  494.                             else if (ch = enq)
  495.                                    then action := r_send_ack
  496.                                    else action := r_get_dle;
  497.                  end;
  498.  
  499.         r_get_seq: begin
  500.                      if (read_byte = false)
  501.                        then action := r_send_nak
  502.                        else if (ch = enq)
  503.                               then action := r_send_ack
  504.                               else
  505.                                 begin
  506.                                   checksum := 0;
  507.                                   block_num := ch - ord('0');
  508.                                   do_checksum(ch);
  509.                                   i := 0;
  510.                                   action := r_get_data;
  511.                                 end;
  512.  
  513.                    end;
  514.  
  515.         r_get_data: begin
  516.                       if (read_masked_byte = false)
  517.                         then action := r_send_nak
  518.                         else if ((ch = etx) and not masked)
  519.                                then
  520.                                  begin
  521.                                    do_checksum(etx);
  522.                                    action := r_get_checksum;
  523.                                  end
  524.                                else
  525.                                  begin
  526.                                    r_buffer[i] := ch;
  527.                                    i := i + 1;
  528.                                    do_checksum(ch);
  529.                                  end;
  530.  
  531.                     end;
  532.  
  533.         r_get_checksum: begin
  534.                           if (read_masked_byte = false)
  535.                             then action := r_send_nak
  536.                             else if (ch <> checksum)
  537.                                    then action := r_send_nak
  538.                                    else if (block_num = seq_num)
  539.                                           then
  540.                                             begin
  541.                                               if (r_buffer[0] = ord('F'))
  542.                                                 then
  543.                                                   begin
  544.                                                     seq_num := block_num;
  545.                                                     r_size := i;
  546.                                                     read_packet :=  true;
  547.                                                     exit;
  548.                                                   end
  549.                                                 else
  550.                                                   action := r_send_ack;
  551.                                             end
  552.                                           else if (block_num <> next_seq)
  553.                                                  then action := r_send_nak
  554.                                                  else
  555.                                                    begin
  556.                                                      seq_num := block_num;
  557.                                                      r_size := i;
  558.                                                      read_packet :=  true;
  559.                                                      exit;
  560.                                                    end;
  561.  
  562.                         end;
  563.  
  564.         r_send_nak: begin
  565.                       errors := errors + 1;
  566.                       if (errors > max_errors)
  567.                         then begin
  568.                                read_packet := false;
  569.                                exit;
  570.                           end;
  571.                       send_nak;
  572.                       action := r_get_dle;
  573.                     end;
  574.  
  575.         r_send_ack: begin
  576.                       send_ack;
  577.                       action := r_get_dle;        { wait for the next block }
  578.                     end;
  579.       end;
  580.     end;
  581.  
  582. end; { Read_Packet }
  583.  
  584. function  write_file(var data_file : bytefile; r_buffer : buffertype;
  585.                      n, size : integer) : integer;
  586.  
  587. var i : integer;
  588.  
  589. begin
  590.   for i := 1 to size do
  591.     write(data_file,r_buffer[n + i - 1]);
  592. end;
  593.  
  594. function receive_file(name : lstr) : boolean;
  595.  
  596. var
  597.   data_file : bytefile;
  598.   status : integer;
  599.  
  600. begin
  601.  
  602.   assign(data_file,name);
  603. {$i-}
  604.   rewrite(data_file);
  605. {$I+}
  606.  
  607.   if (ioresult > 0)
  608.     then
  609.       begin
  610.         send_failure('E');
  611.         begin
  612.           receive_file := false;
  613.           exit;
  614.         end
  615.       end;
  616.  
  617.   send_ack;
  618.  
  619.   while true do
  620.     begin
  621.  
  622.       if (read_packet = true)
  623.         then
  624.           begin
  625.  
  626.             case chr(r_buffer[0]) of
  627.               'N': begin
  628.                      status := write_file(data_file,r_buffer,1,r_size - 1);
  629.                      send_ack;
  630.                    end;
  631.  
  632.               'T': begin
  633.                      if r_buffer[1] = ord('C') then
  634.                          begin
  635.                            writeln('Transfer Complete');
  636.                            close(data_file);
  637.                            send_ack;
  638.                            receive_file :=  true;
  639.                            exit;
  640.                          end;
  641.  
  642.                    end;
  643.  
  644.               'F': begin
  645.                      send_ack;
  646.                      receive_file := false;
  647.                      exit;
  648.                    end;
  649.  
  650.             end;
  651.  
  652.           end;
  653.  
  654.     end;
  655.  
  656. end; { Receive_File }
  657.  
  658. begin
  659.  
  660.   xoff_flag := false;
  661.   r_counter := 0;
  662.   s_counter := 0;
  663.   seq_num := 0;
  664.   send_ack;
  665.  
  666.   if (read_packet = true)
  667.     then
  668.       begin
  669.  
  670.         case chr(r_buffer[0]) of
  671.           'T': begin
  672.                  case chr(r_buffer[1]) of
  673.                    'D' : write('Receiving ');
  674.                    'U' : write('Sending ');
  675.                    else
  676.                      begin
  677.                        send_failure('N');
  678.                        exit;
  679.                      end;
  680.                  end;
  681.  
  682.                  case chr(r_buffer[2]) of
  683.                    'A': write('ASCII file "');
  684.                    'B': write('Binary file "');
  685.                    else
  686.                      begin
  687.                        send_failure('N');        { not implemented }
  688.                        do_transfer := false;
  689.                        exit;
  690.                      end;
  691.                  end;
  692.  
  693.                  i := 2;
  694.                  filename := '';
  695.  
  696.                  while (r_buffer[i] <> 0) and (i < r_size) do
  697.                    begin
  698.                    i := i + 1;
  699.                    filename := filename + chr(r_buffer[i]);
  700.                    end;
  701.  
  702.                  writeln(filename,'"');
  703.  
  704.                  if (r_buffer[1] = ord('U'))
  705.                    then
  706.                      dummy := send_file(filename)
  707.                    else
  708.                      dummy := receive_file(filename);
  709.  
  710.                end;
  711.         end;
  712.       end
  713.     else
  714.       writeln('Cannot receive initial packet, transfer aborted');
  715.  
  716. end; { Do_Transfer }
  717.  
  718.